package com.bsj.power.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bsj.power.common.config.cached.RedisCached;
import com.bsj.power.common.config.global.JsonResult;
import com.bsj.power.common.config.redis.RedisConstant;
import com.bsj.power.common.config.rocketmq.producer.BaseMqPushUtil;
import com.bsj.power.common.constant.MqTopicAndTagConstants;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.def.dto.AlertDTO;
import com.bsj.power.common.def.entity.log.SysExceptionLog;
import com.bsj.power.common.def.vo.WebSocketMsgVO;
import com.bsj.power.common.def.vo.sys.alert.AlertsBody;
import com.bsj.power.common.def.vo.sys.alert.IAlertValueVO;
import com.bsj.power.common.def.vo.sys.alert.OAlertValueVO;
import com.bsj.power.common.mapper.SysExceptionLogMapper;
import com.bsj.power.common.util.ExceptionUtil;
import com.bsj.power.system.service.AlertManagerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;

/**
 * @author : zhuojie.c
 * @version V1.0
 * @Description: TODO
 * @date Date : 2024年08月22日
 */
@Slf4j
@Service
public class AlertManagerServiceImpl implements AlertManagerService {

    /**
     * CPU
     */
    private final int CPU = 1;
    /**
     * 内存
     */
    private final int MEMORY = 2;
    /**
     * 硬盘
     */
    private final int DISK = 3;

    @Autowired
    private BaseMqPushUtil baseMqPushUtil;

    @Autowired
    private RedisCached redisCached;

    @Resource
    private SysExceptionLogMapper exceptionLogMapper;

    @Override
    public void send(String payload) {
        AlertsBody alertsBody = JSONObject.parseObject(payload, AlertsBody.class);
        if (alertsBody != null && CollectionUtil.isNotEmpty(alertsBody.getAlerts())) {
            alertsBody.getAlerts().forEach(v -> {
                try {
                    // 获取当前服务器资源使用率
                    String value = v.getAnnotations().getValue();
                    if (value == null) {
                        return;
                    }
                    double valueDouble = Double.parseDouble(value);
                    // 报警概要
                    String summary = v.getAnnotations().getSummary();
                    // 获取报警类型
                    int exceptionType = getExceptionType(summary);
                    AlertDTO alertDTO = checkIsPushAlarm(exceptionType, valueDouble);
                    // 检查是否推送报警通知
                    if (alertDTO.getFlag()) {
                        // 服务器异常记录
                        SysExceptionLog exceptionLog = new SysExceptionLog();
                        // 服务器报警名称
                        exceptionLog.setName(v.getAnnotations().getSummary());
                        // 服务器实例名称
                        String instance = v.getAnnotations().getInstance();
                        int index = instance.indexOf(":");
                        if (index != -1) {
                            String ip = instance.substring(0, index);
                            // 服务IP地址
                            exceptionLog.setIp(ip);
                        } else {
                            exceptionLog.setIp(instance);
                        }
                        // 服务器异常类型
                        exceptionLog.setExceptionType(exceptionType);
                        // 服务器异常内容
                        exceptionLog.setContent(v.getAnnotations().getDescription() + ":" + alertDTO.getValue() + "%，当前使用率：" + value + "%");
                        exceptionLog.setCreateTime(new Date());
                        // 保存成功
                        if (exceptionLogMapper.insert(exceptionLog) > 0) {
                            try {
                                WebSocketMsgVO webSocketMsgVO = WebSocketMsgVO.builder()
                                        .msgType(NumericalConstants.FOUR)
                                        .obj(exceptionLog)
                                        .build();
                                baseMqPushUtil.sendTopicBytes(MqTopicAndTagConstants.SYSTEM_WEB_SERVER_CHANGE_TOPIC,
                                        MqTopicAndTagConstants.SYSTEM_WEB_PRODUCT_CHANGE_TAG, JSON.toJSONBytes(webSocketMsgVO));
                            } catch (Exception e) {
                                log.error("推送服务器异常错误：{}", ExceptionUtil.getStackStr(e));
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("保存服务器异常日志错误：{}", ExceptionUtil.getStackStr(e));
                }
            });
        }
    }

    @Override
    public JsonResult setAlertValue(IAlertValueVO alertValueVO) {
        boolean cpuFlag = redisCached.set(RedisConstant.SYS_CPU_THRESHOLD, alertValueVO.getCpuValue());
        boolean memoryFlag = redisCached.set(RedisConstant.SYS_MEMORY_THRESHOLD, alertValueVO.getMemoryValue());
        boolean diskFlag = redisCached.set(RedisConstant.SYS_DISK_THRESHOLD, alertValueVO.getDiskValue());
        if (cpuFlag && memoryFlag && diskFlag) {
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    @Override
    public JsonResult<OAlertValueVO> getAlertValue() {
        OAlertValueVO alertValueVO = new OAlertValueVO();
        String cpuValueStr = redisCached.get(RedisConstant.SYS_CPU_THRESHOLD);
        if (cpuValueStr != null) {
            alertValueVO.setCpuValue(Integer.parseInt(cpuValueStr));
        }
        String memoryValueStr = redisCached.get(RedisConstant.SYS_MEMORY_THRESHOLD);
        if (memoryValueStr != null) {
            alertValueVO.setMemoryValue(Integer.parseInt(memoryValueStr));
        }
        String diskValueStr = redisCached.get(RedisConstant.SYS_DISK_THRESHOLD);
        if (diskValueStr != null) {
            alertValueVO.setDiskValue(Integer.parseInt(diskValueStr));
        }
        return JsonResult.success(alertValueVO);
    }

    /**
     * 获取异常类型
     *
     * @param content
     * @return
     */
    private int getExceptionType(String content) {
        int exceptionType;
        switch (content) {
            case "CPU使用率告警":
                exceptionType = CPU;
                break;
            case "内存使用率告警":
                exceptionType = MEMORY;
                break;
            case "磁盘使用率告警":
                exceptionType = DISK;
                break;
            default:
                exceptionType = 0;
                break;
        }
        return exceptionType;
    }

    /**
     * 检查是否推送报警
     *
     * @param exceptionType 报警类型
     * @param value         资源使用率
     * @return
     */
    private AlertDTO checkIsPushAlarm(int exceptionType, double value) {
        AlertDTO alertDTO = new AlertDTO();
        boolean flag = false;
        // 服务器报警通知阀值未设置的时候，初始值为80
        int systemSetValue = 80;
        switch (exceptionType) {
            case CPU:
                String cpuValueStr = redisCached.get(RedisConstant.SYS_CPU_THRESHOLD);
                if (cpuValueStr != null) {
                    systemSetValue = Integer.parseInt(cpuValueStr);
                }
                break;
            case MEMORY:
                String memoryValueStr = redisCached.get(RedisConstant.SYS_MEMORY_THRESHOLD);
                if (memoryValueStr != null) {
                    systemSetValue = Integer.parseInt(memoryValueStr);
                }
                break;
            case DISK:
                String diskValueStr = redisCached.get(RedisConstant.SYS_DISK_THRESHOLD);
                if (diskValueStr != null) {
                    systemSetValue = Integer.parseInt(diskValueStr);
                }
                break;
            default:
                break;
        }
        // 如果超过系统设置的报警阀值，则记录并推送报警通知
        if (value >= systemSetValue) {
            flag = true;
        }
        alertDTO.setFlag(flag);
        alertDTO.setValue(systemSetValue);
        return alertDTO;
    }
}
